package cn.imu.config;

import cn.imu.entity.User;
import cn.imu.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import javax.servlet.http.HttpSession;
import java.util.concurrent.TimeUnit;

/**
 * @author 杨鑫
 */
public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //用户登录次数计数  redisKey 前缀
    private String SHIRO_LOGIN_COUNT = "shiro_login_count_";

    //用户登录是否被锁定  redisKey 前缀
    private String SHIRO_IS_LOCK = "shiro_is_lock_";
    //int  count=0;
    //HttpSession session;



    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了=》授权doGetAuthorizationInfo");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        authorizationInfo.addStringPermission("user:add");
        //拿到当前登录的这个对象
        Subject subject = SecurityUtils.getSubject();
        //拿到user对象
        User currentUser = (User)subject.getPrincipal();
        //设置当前用户的权限
        authorizationInfo.addStringPermission(currentUser.getPerms());
        return authorizationInfo;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=》认证doGetAuthenticationInfo");
        //拿到用户名密码令牌
        UsernamePasswordToken userToken=(UsernamePasswordToken)  authenticationToken;
        String userName=userToken.getUsername();
        String userPassword=new String(userToken.getPassword());
        System.out.println("userName:"+userName);
        System.out.println("userPassword:"+userPassword);

        //连接真实数据库
        User user = userService.queryUserByName(userToken.getUsername());
       //登录成功后，在session中放值，便于判断
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginUser",user);

        if(user==null){
            throw new UnknownAccountException("账号不存在！");
        }else if(!user.getPwd().equals(userPassword)){

            //访问一次，计数一次
            ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
            //count++;
            //每次增加1
        /*
        9、increment(K key, double delta)
        以增量的方式将double值存储在变量中。
       double stringValueDouble=redisTemplate.opsForValue().increment("doubleKey",5);
         */
            opsForValue.increment(SHIRO_LOGIN_COUNT+userName,1);

            //缓存中用户登录的次数
            int keyCount=Integer.parseInt(opsForValue.get(SHIRO_LOGIN_COUNT+userName));
           // opsForValue.set(SHIRO_LOGIN_COUNT+userName,String.valueOf(count));
            //System.out.println("aaaaaa");
            System.out.println(keyCount);
            System.out.println(userName+": 账户登录的次数是： "+keyCount);
            if(keyCount<3) {
                throw new IncorrectCredentialsException("密码不正确！");
            }
            //实现锁定
            if(keyCount>=3){
                opsForValue.set(SHIRO_IS_LOCK+userName, "LOCK");  //锁住这个账号，值是LOCK。
                //expire  变量存活期限，设置过期时间为1分钟
                stringRedisTemplate.expire(SHIRO_IS_LOCK+userName, 1, TimeUnit.MINUTES);

            }
            //如果这个账号登陆异常，则在登陆页面提醒
            if(keyCount>=3){
                //读出redis中的值放到shrio的session中，判断其是否大于0
                session.setAttribute("count",keyCount);
                if("LOCK".equals(opsForValue.get(SHIRO_IS_LOCK+userName))){

                    //count=0;
                    //清空登录计数
                    opsForValue.set(SHIRO_LOGIN_COUNT+userName, "0");
                    //清空锁
                    opsForValue.set(SHIRO_IS_LOCK+userName, "");
                    //计数大于3次，设置用户被锁定一分钟

                    throw new LockedAccountException("由于输入错误次数大于3次，帐号1分钟内已经禁止登录！");
                }
            }



        }



        //密码认证，shiro做,加密了,MD5,MD5加盐
        //将user返回，用于授权
        SimpleAuthenticationInfo simpleAuthenticationInfo =
                new SimpleAuthenticationInfo(user.getName(), user.getPwd(),getName());


        return simpleAuthenticationInfo;


    }
}
